02A pairs experiments
Experiment-related scripts
Read pairwise competition outcomes that are determined by colony
counts on plates.
Read CASEU results
Map pairs and isolates to the 96-well plate layout
Read the pairwise competitive outcomes determined by colony counting
on TSA
The script below generates the table for manual keyin
if (FALSE) source("script/02A-pairs_experiment-01-pairwise_manual_key_in.R")
Then I manually checked the scanned plate images of competitive
pairs. The plate images are saved in folder
data/raw/plate_scan/emergent_coexistence_plate_scan/
divided according to the experimental batches.
| B2 |
2.6, 2.8, 7.1, 8.4, 10.2, 11.1 |
| C |
11.1 isolate 1 |
| C2 |
11.2 |
| D |
1.2, 1.4, 1.6, 1.7, 4.1, 11.5 |
# Read result colony counts and dilution factor
if (run_scripts) source("script/02A-pairs_experiment-02-colony_count.R")
There are 186x3=558 outcomes of pairwise competitions.
pairs_competition <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_competition.csv", col_types = cols())
pairs_competition
67 of of 558 pair-frequency without determined outcomes of pairwise
competitions will be determined by using CASEU method
pairs_competition %>% filter(is.na(ColonyCount))
186 pair IDs saved in data/temp/pairs_ID.csv
pairs_ID <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_ID.csv", col_types = cols())
pairs_ID
Ambiguous pairs and isolates on TSA agar plates
if (run_scripts) source("script/02A-pairs_experiment-03-pairwise_ambiguous.R")
There are 67 pair-freqs that the competition outcome cannot be
determined by TSA plate counting because of ambiguous morphology. The
ambiguous pairs will be later examined by using selective media or
Sanger sequencing.
pairs_ambiguous <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_ambiguous.csv", col_types = cols())
pairs_ambiguous
In total, 28 pairs
pairs_ambiguous %>%
group_by(Community, Isolate1, Isolate2) %>%
summarize(Count = n(), .groups = "keep")
36 isolates involved in the ambiguous pairs.
isolates_ambiguous <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/isolates_ambiguous.csv", col_types = cols())
isolates_ambiguous
Map pairs and isolates to the DW96 plate layout
if (run_scripts) source("script/02A-pairs_experiment-04-pairwise_plate_layout.R")
Each plate has 96 rows and has the following variables
plates <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/plates.csv", col_types = cols())
plates
Plates for across-community and random assembly
plates_random <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/plates_random.csv", col_types = cols())
plates_random
plates_list <- plates %>%
filter(Plate == "P1") %>%
distinct(Batch, PlateLayout) %>%
rename(batch = Batch, platelayout = PlateLayout) %>%
rowwise() %>%
mutate(plate = filter(plates, Batch == batch, PlateLayout == platelayout, Plate == "P1") %>% list) %>%
mutate(plate = prepare_plate_draw(plate) %>% list) %>%
mutate(p_plate = draw_plate_from_df(plate) %>% list)
plot_grid(plotlist = plates_list$p_plate, labels = paste0(plates_list$batch, " ", plates_list$platelayout),
ncol = 2)
Warning: Removed 2 rows containing missing values (geom_text).

Plate layout that takes different initial frequencies:
The only exception is plate C11R1 in batch C, which only has one
plate.
OD <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/OD.csv", col_types = cols())
OD %>%
filter(Community == "C1R2", Wavelength == 620) %>%
ggplot(aes(x = Transfer, y = Abs, color = Isolate1Freq)) +
geom_line() + geom_point() +
facet_grid(Isolate1 ~ Isolate2) +
theme_classic()

NA
02B CASEU sanger sequencing
To determine the relative abundance of of ambiguous pairs in
competitive assays.
Use CASEU packages to analyse the Sanger sequencing of mixture
culture.
Sanger sequencing protocol preparation. Experimental protocol
files are saved in folder output/protocol/
list.files(here::here("output/protocol"), pattern = "caseu")
Once we got the mixture Sanger sequences back, we implement
analysis by using CASEU (Compositional analysis by Sanger
electropherogram unmixing), an R package designed for quantifying
relative abundance of Sanger sequences mixture. source code. Install
CASEU from bitbucket.
Check out package
vignette.
devtools::install_bitbucket('dattamanoshi/caseu') # Install CASEU package
library(CASEU)
Test on example data
if (run_scripts) source("script/02B-CASEU_sanger_seq-00-test.R")
CASEU pilot1
The plate layout of PCR plate and list of samples are specified in
output/protocol/protocol_20190813_Sanger_seq_prep.pdf.
read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot1/protocol_20190813_Sanger_seq_prep-genewiz_table.csv", col_types = cols())
The isolates used in this round is from the list below.
isolates
| C11R1 isolate 1 |
A |
Pseudomonas |
| C1R7 isolate 2 |
B |
Pseudomonas |
| C1R7 isolate 1 |
C |
Enterobacter |
| C1R7 isolate 7 |
D |
Raoultella |
Read trace matrices for isolates and mixtures
if (run_scripts) source("script/02B-CASEU_sanger_seq-01-pilot1.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot1.csv", col_types = cols())
CASEU pilot2
The plate layout of PCR plate and list of samples are specified in
output/protocol/protocol_20190813_Sanger_seq_prep.pdf.
There are 32 samples from pairwise competition and 16 samples from
control. Also read Sylvie’s data.
read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot2/protocol_20190910_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())
Isolates A B C D in control are the isolates below.
| C11R1 isolate 1 |
A |
Pseudomonas |
| C1R7 isolate 2 |
B |
Pseudomonas |
| C1R7 isolate 1 |
C |
Enterobacter |
| C1R7 isolate 7 |
D |
Raoultella |
if (run_scripts) source("script/02B-CASEU_sanger_seq-02-pilot2.R")
#source("script/02B-CASEU_sanger_seq-02a-pilot2_Sylvie.R") # Run Sylvie's sequence
In the 12 control synthetic pairs that were made of 4 isolates,
compare these pairs’ OD frequencies, colony counts, and CASEU
predictions.
Read CASEU predicted frequencies and colony count frequencies in the
12 control pairs.
CASEU_pilot2 <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot2.csv", col_types = cols())
CASEU_pilot2_plating <- read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot2/CASEU_pilot2_plating.csv", col_types = cols()) %>%
mutate(Isolate1ColonyFreq = Isolate1Colony / (Isolate1Colony + Isolate2Colony),
Isolate2ColonyFreq = Isolate2Colony / (Isolate1Colony + Isolate2Colony))
CASEU_pilot2
CASEU pilot3
The plate layout of PCR plate and list of samples are specified in
output/protocol/protocol_20190923_SequalPrep_Sanger_prep.pdf.
read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot3/protocol_20190924_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())
Read trace matrices for isolates and mixtures
# It takes about ~15 mins to run
if (run_scripts) source("script/02B-CASEU_sanger_seq-03-pilot3.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot3.csv", col_types = cols())
CASEU pilot4
The plate layout of PCR plate and list of samples are specified in
output/protocol/protocol_20191007_Sanger_seq_prep.pdf.
read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot4/protocol_20191007_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())
Read trace matrices for isolates and mixtures
# It takes about ~15 mins to run
if (run_scripts) source("script/02B-CASEU_sanger_seq-04-pilot4.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot4.csv", col_types = cols())
CASEU six plates
- Genewiz submission code: CASEU_RN_5 (which is not correct because
these are not RN plates)
- Plates:
- B2 T7 933 P2
- B2 T7 444 P2
- C2 T7 13A P2
- C2 T7 13B P2
- D T7 75 P2
- D T7 5543 P2
- Notes: the plates must be placed in order!!
# Generate sequencing csv
if (FALSE) {
genewiz_table <- tibble(Sample = 1:(96*6),
`DNA Name` = paste0(rep(c("B2_T7_933_P2", "B2_T7_444_P2", "C2_T7_13A_P2", "C2_T7_13B_P2", "D_T7_75_P2", "D_T7_5543_P2"), each = 96), "_", rep(1:96, 6)),
`Length (bp)` = 1000, `Concentration (ng/uL)` = 0.83, Primer = "27F")
write_csv(genewiz_table, here::here("output/protocol/tab_fig/20211202_Sanger_seq_prep-genewiz_table_CYC.csv"))
}
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_sixplates.csv", col_types = cols())
Random network, CASEU batch 1
- Genewiz submisstion code: Caseu_RN_1
- Plate layout: T3 C P2
- Description: samples 3, 4, 5, 12, 13, 27, 29, 33, 73, 85, 86, 91,
and 94 (order by column in the plate layout) arrived Genewiz dry, so
they are not processed.
# If will take ~2 hr to run
if (run_scripts) source("script/02B-random_network_CASEU-01-batch1.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN1.csv", col_types = cols())
Random network, CASEU batch 2
- Genewiz submission code: Caseu_RN_2
- Plate layout: T3 C P2
- Description: this plate layout contains the isolates for all 4
random assembled communities
# It takes ~30 mins
if (run_scripts) source("script/02B-random_network_CASEU-02-batch2.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN2.csv", col_types = cols())
Random network, CASEU batch 3
- Genewiz submisstion code: Caseu_RN_3
- Plate layout:
- P1 (T0 C P2), tracking number 30-333649143
- P2 (T0 AD P2), tracking number 30-333649365
- P3 (T3 AD P2), tracking number 30-333649517
- Description: AD plates have the isolates assembled from the
self-assembled communities but different communities
# It takes ~1.5 hr
if (run_scripts) source("script/02B-random_network_CASEU-03-batch3.R")
Use T0 OD frequencies
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN3.csv", col_types = cols())
Random network, CASEU batch 4
- Genewiz submisstion code: Caseu_RN_4
- Plate layout: T3 BD P3
- Description: This plate has the full AcrAss2 (B) and half of RanAss2
(D) network.
if (run_scripts) source("script/02B-random_network_CASEU-04-batch4.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN4.csv", col_types = cols())
02C pairs_OD_CFU
Error propagation theory
Derive isolates’ \(\epsilon\)
from T8 data and calculate uncertatinty using error propagation
theory
Convert T0 OD frequency \(f^O\)
to CFU frequency \(f^C\) and estimate
the uncertainty in converted CFU frequencies at T8. Output
data/temp/pairs_CFU_freq_uncertainty.csv
Uncertainty in epsilon
if (run_scripts) source("script/02C-pairs_OD_CFU-01-epsilon_uncertainty.R")
The uncertainties in each isolate’ epsilon \(\epsilon_A = \frac{OD_A DF_A v_A}{CFU_A}\)
comes from four parts:
- \(DF\): Dilution factors. The
uncertainty comes from the pipetting in serial dilution, which is
calcaulted below.
- \(v\): Plating volumes. The
systematic error for P20 set at 20 uL is 0.4 uL.
- \(CFU\): CFU counts. The
uncertainty in CFU follows poisson distribution, which means that the
variance is the same as the mean (measured CFU). The standard deviation
is \(\sqrt{CFU}\).
- \(OD\): OD measurement. The
uncertainty in measuring OD in plate reader, which is assumed to be
0.001.
Dilution factor
The uncertainty in dilution factor comes from the pipetting steps in
serial dilution, which include two pipetting volumes:
V1: serial dispensing 10 uL of diluted solution using
mP20. It has uncertainty ErrorV1 2 uL.
V2: dispense 90 uL of PBS using mP200. It has
uncertainty ErrorV2 0.4 uL.
For dilution factor \(10^{n}\), it
has the the mean \((\frac{V_1}{V_1+V_2})^n\). To obtain the
uncertainty in the measured mean, first we caluculate the partial
derivatives \(\frac{\partial DF}{\partial
V_1}\) and \(\frac{\partial
DF}{\partial V_2}\). Then the uncertainty \(\delta DF = \sqrt{(\frac{\partial DF}{\partial
V_1}\delta V_1)^2 + (\frac{\partial DF}{\partial V_2}\delta
V_2)^2}\)
dilution_factor <- tibble(n = c(4, 5), V1 = 10, V2 = 90, ErrorV1 = 0.4, ErrorV2 = 2) %>%
mutate(PartialV1 = n * V1^(n-1) * V2 / (V1+V2)^(n+1), #-n*(V1+V2)^(n-1)*V2/(V1^(n+1)),
PartialV2 = -n * V1^(n-1) / (V1+V2)^(n+1), #n*(V1+V2)^(n-1)/(V1^n),
DF = (V1/(V1+V2))^n,
ErrorDF = sqrt((PartialV1*ErrorV1)^2 + (PartialV2*ErrorV2)^2))
dilution_factor
By using error propagation theroy, the uncertainty in isolates
epsilon has the form
\[\delta \epsilon =
\sqrt{(\frac{\partial \epsilon}{\partial DF}\delta DF)^2
+(\frac{\partial \epsilon}{\partial CFU}\delta CFU)^2 +
(\frac{\partial \epsilon}{\partial OD}\delta OD)^2 +
(\frac{\partial \epsilon}{\partial V}\delta V)^2}\]
isolates_epsilon_uncertainty <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/isolates_epsilon_uncertainty.csv", col_types = cols())
isolates_epsilon_uncertainty
NA
There are 7 isolates that have either 0 CFU or negative OD value, so
they don’t have epsilon values.
isolates_epsilon_uncertainty %>%
filter(is.na(Epsilon))
Convert T0 OD frequencies to CFU frequencies
if (run_scripts) source("script/02C-pairs_OD_CFU-02-CFU_frequency.R")
The outcome of pairwise competition were determined by comparing the
frequency changes between T0 and T8. The T8 frequencies were determined
by plating the mature media on rich agar media on which the colonies
were counted, whereas T0 frequencies were set to 95/5, 50/50 and 5/95 by
mixing two isolate inocula with equal OD. In this section, I will use
the OD-CFU conversion coefficient \(\epsilon\) derived from T8 isolate data to
convert T0 OD frequencies into CFU frequencies. In specific, the CFU
frequency of isolate 1 \(f^C_1\) of a
pair can be derived from OD frequencies of isolate 1 and 2 \(f^O_1 ,f^O_2\), which have the relationship
below.
\(f^C_1 =
\frac{f^o_1\epsilon_1DFv}{f^o_1\epsilon_1DFv +
f^o_2\epsilon_2DFv}=\frac{f^o_1\epsilon_1}{f^o_1\epsilon_1 +
f^o_2\epsilon_2}\)
where \(\epsilon\) of each isolate
was pre-calculated from T8 dataset. DF and v are the same in
conversion.
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_CFU_freq.csv", col_types = cols())
Uncertainty in T0 CFU frequencies
if (run_scripts) source("script/02C-pairs_OD_CFU-03-CFU_frequency_uncertainty.R")
Write CFU frequencies to
data/temp/pairs_CFU_freq_uncertainty.csv
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_CFU_freq_uncertainty.csv", col_types = cols())
02D determine pairwise interaction
Combine outcomes of pairwise competition from CFU counts and
CASEU
Raw data (e.g., CFU counts and CASEU Sanger sequences) are processed
and generated into temporary result csv:
02B-CASEU_sanger_seq reads CASEU raw data and
outputs temp/CASEU_pilot2.csv and
temp/CASEU_pilot3.csv. Both files are CASEU predicted T8
frequencies.
02C-pairs_OD_CFU reads pair_competition and dilution
factor data, and it outputs
temp/pairs_CFU_freq_uncertainty.csv, which has the T0
OD-converted CFU frequencies and T8 CFU frequencies with
uncertainties.
if (run_scripts) source("script/02D-determine_pairwise_interaction-01-combine_CFU_CASEU_result.R")
The script in this section returns a data.frame
pairs_freq that has the following variables:
Community
Isolate1 and Isolate2: indices of isolates
within a community. The number of isolate1 is always smaller than
isolate2
Isolate1InitialODFreq and
Isolate2InitialODFreq: 5, 50 or 95. The initial OD
frequencies of isolates at T0. This two serve as discrete grouping
variables.
Time: T0 or T8.
Isolate1MeasuredFreq: the measured frequency od
isolate1 in the pair.
ErrorIsolate1MeasuredFreq: the uncertainty of
Isolate1MeasuredFreq.
RawDataType: OD, ODtoCFU, CFU, Sanger (CASEU). The raw
data type in which the isolate frequencies were measured.
Contamination: logical. There are contamination in
three pairs at T8 plates.
186x3x2=1116 pair-freq at two time points for the self-assembled
community networks.
read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_freq.csv", col_types = cols())
Determine pairwise interactions
if (run_scripts) source("script/02D-determine_pairwise_interaction-02-determine_pairwise_interaction.R")
Table of all 27 + 4 possible combinations of fitness function and
their interaction types
read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_interaction_table.csv", col_types = cols())
Table of interaction types
pairs_interaction_fitness <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_interaction_fitness.csv", col_types = cols())
pairs_interaction_fitness %>%
group_by(Set, InteractionType) %>%
summarize(Count = n(), .groups = "keep")
Isolate tournament
if (run_scripts) source("script/02D-determine_pairwise_interaction-03-isolate_tournament.R")
Tournament ranks of each isolate. Note that I consider neturality and
bistability as draw in the tournament.
Score: the competitive scores of isolate. This score is
computed by the formula: number of wins - number of loses + 0 * number
of draws.
Game: number of pairwise competition the isolate has
played. The number of games an isolate plated within a community should
be community size minus one.
Rank: the ranks based on Score. The ranks
range from 1 to the focal community size. Isolates with the same scores
in a community are given the same rank.
PlotRank: continuous rank for plotting
convenience.
Summary
Read and combine pairs data
if (run_scripts) source("script/02-pairs-01-read_data.R")
186 pairs of self-assembled communities and 112 pair from
across-community and random networks
Pairs with three initial frequencies and three. 186x3x2=1116
pairs_meta contains the growth traits of isolates. Note that the
order of Isolate1 and Isolate2 in some pairs are flipped such that
Isolate1 is always the dominant strain and Isolate 2 is the subdomaint
one. Dominant strain is the winner in exclusion pairs, and the more
abundant strain (50:50 treatment) in coexistence pairs.
if (FALSE) pairs_meta <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_meta.csv", col_types = cols())
Example outcome types
if (run_scripts) source("script/02-pairs-02-outcome_types.R")
Coarse-grained
Fine-grained
read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_example_outcomes_finer.csv", col_types = cols())
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb24gcGFpcndpc2UgY29tcGV0aXRpb24gYXNzYXlzIgphdXRob3I6ICJDaGFuZy1ZdSBDaGFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgZWNobyA9IFRSVUUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCnNvdXJjZShoZXJlOjpoZXJlKCJwbG90dGluZ19zY3JpcHRzL21pc2MuUiIpKQpydW5fc2NyaXB0cyA8LSBGCmBgYAoKCiMgMDJBIHBhaXJzIGV4cGVyaW1lbnRzCgotIEV4cGVyaW1lbnQtcmVsYXRlZCBzY3JpcHRzCgotIFJlYWQgcGFpcndpc2UgY29tcGV0aXRpb24gb3V0Y29tZXMgdGhhdCBhcmUgZGV0ZXJtaW5lZCBieSBjb2xvbnkgY291bnRzIG9uIHBsYXRlcy4gCgotIFJlYWQgQ0FTRVUgcmVzdWx0cwoKLSBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSA5Ni13ZWxsIHBsYXRlIGxheW91dAoKCiMjIFJlYWQgdGhlIHBhaXJ3aXNlIGNvbXBldGl0aXZlIG91dGNvbWVzIGRldGVybWluZWQgYnkgY29sb255IGNvdW50aW5nIG9uIFRTQQoKVGhlIHNjcmlwdCBiZWxvdyBnZW5lcmF0ZXMgdGhlIHRhYmxlIGZvciBtYW51YWwga2V5aW4KCmBgYHtyfQppZiAoRkFMU0UpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAxLXBhaXJ3aXNlX21hbnVhbF9rZXlfaW4uUiIpCmBgYAoKVGhlbiBJIG1hbnVhbGx5IGNoZWNrZWQgdGhlIHNjYW5uZWQgcGxhdGUgaW1hZ2VzIG9mIGNvbXBldGl0aXZlIHBhaXJzLiBUaGUgcGxhdGUgaW1hZ2VzIGFyZSBzYXZlZCBpbiBmb2xkZXIgYGRhdGEvcmF3L3BsYXRlX3NjYW4vZW1lcmdlbnRfY29leGlzdGVuY2VfcGxhdGVfc2Nhbi9gIGRpdmlkZWQgYWNjb3JkaW5nIHRvIHRoZSBleHBlcmltZW50YWwgYmF0Y2hlcy4KCkJhdGNoIHwgQ29tbXVuaXR5Ci0tLS0tLXwtLS0tLS0tLS0tLQpCMiAgICB8IDIuNiwgMi44LCA3LjEsIDguNCwgMTAuMiwgMTEuMQpDICAgICB8IDExLjEgaXNvbGF0ZSAxCkMyICAgIHwgMTEuMgpEICAgICB8IDEuMiwgMS40LCAxLjYsIDEuNywgNC4xLCAxMS41CgoKYGBgIHtyfQojIFJlYWQgcmVzdWx0IGNvbG9ueSBjb3VudHMgYW5kIGRpbHV0aW9uIGZhY3RvcgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAyLWNvbG9ueV9jb3VudC5SIikKYGBgCgpUaGVyZSBhcmUgMTg2eDM9NTU4IG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9ucy4KCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfY29tcGV0aXRpb24uY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwYWlyc19jb21wZXRpdGlvbgpgYGAKCjY3IG9mIG9mIDU1OCBwYWlyLWZyZXF1ZW5jeSB3aXRob3V0IGRldGVybWluZWQgb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zIHdpbGwgYmUgZGV0ZXJtaW5lZCBieSB1c2luZyBDQVNFVSBtZXRob2QKCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiAlPiUgZmlsdGVyKGlzLm5hKENvbG9ueUNvdW50KSkKYGBgCgoxODYgcGFpciBJRHMgc2F2ZWQgaW4gYGRhdGEvdGVtcC9wYWlyc19JRC5jc3ZgCgpgYGB7cn0KcGFpcnNfSUQgPC0gcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX0lELmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfSUQKYGBgCgoKCiMjIEFtYmlndW91cyBwYWlycyBhbmQgaXNvbGF0ZXMgb24gVFNBIGFnYXIgcGxhdGVzCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkEtcGFpcnNfZXhwZXJpbWVudC0wMy1wYWlyd2lzZV9hbWJpZ3VvdXMuUiIpCmBgYAoKClRoZXJlIGFyZSA2NyBwYWlyLWZyZXFzIHRoYXQgdGhlIGNvbXBldGl0aW9uIG91dGNvbWUgY2Fubm90IGJlIGRldGVybWluZWQgYnkgVFNBIHBsYXRlIGNvdW50aW5nIGJlY2F1c2Ugb2YgYW1iaWd1b3VzIG1vcnBob2xvZ3kuIFRoZSBhbWJpZ3VvdXMgcGFpcnMgd2lsbCBiZSBsYXRlciBleGFtaW5lZCBieSB1c2luZyBzZWxlY3RpdmUgbWVkaWEgb3IgU2FuZ2VyIHNlcXVlbmNpbmcuIAoKYGBge3J9CnBhaXJzX2FtYmlndW91cyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfYW1iaWd1b3VzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfYW1iaWd1b3VzCmBgYAoKSW4gdG90YWwsIDI4IHBhaXJzCgpgYGB7cn0KcGFpcnNfYW1iaWd1b3VzICU+JSAKICBncm91cF9ieShDb21tdW5pdHksIElzb2xhdGUxLCBJc29sYXRlMikgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpLCAuZ3JvdXBzID0gImtlZXAiKQpgYGAKCjM2IGlzb2xhdGVzIGludm9sdmVkIGluIHRoZSBhbWJpZ3VvdXMgcGFpcnMuIAoKYGBge3J9Cmlzb2xhdGVzX2FtYmlndW91cyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvaXNvbGF0ZXNfYW1iaWd1b3VzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKaXNvbGF0ZXNfYW1iaWd1b3VzCmBgYAoKCgojIyBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSBEVzk2IHBsYXRlIGxheW91dAoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJBLXBhaXJzX2V4cGVyaW1lbnQtMDQtcGFpcndpc2VfcGxhdGVfbGF5b3V0LlIiKQpgYGAKCkVhY2ggcGxhdGUgaGFzIDk2IHJvd3MgYW5kIGhhcyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcwoKYGBge3J9CnBsYXRlcyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL291dHB1dC9wbGF0ZXMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwbGF0ZXMKYGBgCgoKUGxhdGVzIGZvciBhY3Jvc3MtY29tbXVuaXR5IGFuZCByYW5kb20gYXNzZW1ibHkKCmBgYHtyfQpwbGF0ZXNfcmFuZG9tIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BsYXRlc19yYW5kb20uY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwbGF0ZXNfcmFuZG9tCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gM30KcGxhdGVzX2xpc3QgPC0gcGxhdGVzICU+JQogICAgZmlsdGVyKFBsYXRlID09ICJQMSIpICU+JQogICAgZGlzdGluY3QoQmF0Y2gsIFBsYXRlTGF5b3V0KSAlPiUKICAgIHJlbmFtZShiYXRjaCA9IEJhdGNoLCBwbGF0ZWxheW91dCA9IFBsYXRlTGF5b3V0KSAlPiUKICAgIHJvd3dpc2UoKSAlPiUKICAgIG11dGF0ZShwbGF0ZSA9IGZpbHRlcihwbGF0ZXMsIEJhdGNoID09IGJhdGNoLCBQbGF0ZUxheW91dCA9PSBwbGF0ZWxheW91dCwgUGxhdGUgPT0gIlAxIikgJT4lIGxpc3QpICU+JQogICAgbXV0YXRlKHBsYXRlID0gcHJlcGFyZV9wbGF0ZV9kcmF3KHBsYXRlKSAlPiUgbGlzdCkgJT4lCiAgICBtdXRhdGUocF9wbGF0ZSA9IGRyYXdfcGxhdGVfZnJvbV9kZihwbGF0ZSkgJT4lIGxpc3QpIAoKcGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxhdGVzX2xpc3QkcF9wbGF0ZSwgbGFiZWxzID0gcGFzdGUwKHBsYXRlc19saXN0JGJhdGNoLCAiICIsIHBsYXRlc19saXN0JHBsYXRlbGF5b3V0KSwKICAgICAgICAgIG5jb2wgPSAyKQoKYGBgCgpQbGF0ZSBsYXlvdXQgdGhhdCB0YWtlcyBkaWZmZXJlbnQgaW5pdGlhbCBmcmVxdWVuY2llczoKCi0gUDEgaXMgNTAlOjUwJS4KCi0gUDIgYW5kIFAzIGFyZSBpZGVudGljYWwgYW5kIHdob3NlIHJvd3MgYXJlIDk1JSBhbmQgY29sdW1ucyBhcmUgNSUuCgpUaGUgb25seSBleGNlcHRpb24gaXMgcGxhdGUgQzExUjEgaW4gYmF0Y2ggQywgd2hpY2ggb25seSBoYXMgb25lIHBsYXRlLgoKYGBge3J9Ck9EIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9PRC5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCgpPRCAlPiUKICAgIGZpbHRlcihDb21tdW5pdHkgPT0gIkMxUjIiLCBXYXZlbGVuZ3RoID09IDYyMCkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBUcmFuc2ZlciwgeSA9IEFicywgY29sb3IgPSBJc29sYXRlMUZyZXEpKSArCiAgICBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKSArCiAgICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICAgIHRoZW1lX2NsYXNzaWMoKQogICAgCmBgYAoKCgojIDAyQiBDQVNFVSBzYW5nZXIgc2VxdWVuY2luZwoKLSBUbyBkZXRlcm1pbmUgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBvZiBhbWJpZ3VvdXMgcGFpcnMgaW4gY29tcGV0aXRpdmUgYXNzYXlzLiAKCi0gVXNlIENBU0VVIHBhY2thZ2VzIHRvIGFuYWx5c2UgdGhlIFNhbmdlciBzZXF1ZW5jaW5nIG9mIG1peHR1cmUgY3VsdHVyZS4KCi0gU2FuZ2VyIHNlcXVlbmNpbmcgcHJvdG9jb2wgcHJlcGFyYXRpb24uIEV4cGVyaW1lbnRhbCBwcm90b2NvbCBmaWxlcyBhcmUgc2F2ZWQgaW4gZm9sZGVyIGBvdXRwdXQvcHJvdG9jb2wvYAoKYGBge3J9Cmxpc3QuZmlsZXMoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sIiksIHBhdHRlcm4gPSAiY2FzZXUiKQpgYGAKCi0gT25jZSB3ZSBnb3QgdGhlIG1peHR1cmUgU2FuZ2VyIHNlcXVlbmNlcyBiYWNrLCB3ZSBpbXBsZW1lbnQgYW5hbHlzaXMgYnkgdXNpbmcgYENBU0VVYCAoQ29tcG9zaXRpb25hbCBhbmFseXNpcyBieSBTYW5nZXIgZWxlY3Ryb3BoZXJvZ3JhbSB1bm1peGluZyksIGFuIFIgcGFja2FnZSBkZXNpZ25lZCBmb3IgcXVhbnRpZnlpbmcgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mIFNhbmdlciBzZXF1ZW5jZXMgbWl4dHVyZS4gW3NvdXJjZSBjb2RlXShodHRwczovL2JpdGJ1Y2tldC5vcmcvRGF0dGFNYW5vc2hpL2Nhc2V1KS4gSW5zdGFsbCBgQ0FTRVVgIGZyb20gYml0YnVja2V0LgoKLSBDaGVjayBvdXQgW3BhY2thZ2UgdmlnbmV0dGVdKGh0dHBzOi8vaHRtbHByZXZpZXcuZ2l0aHViLmlvLz9odHRwczovL2JpdGJ1Y2tldC5vcmcvZGF0dGFtYW5vc2hpL2Nhc2V1L3Jhdy9tYXN0ZXIvZG9jL0NBU0VVX1ZpZ25ldHRlLmh0bWwpLgoKYGBge3IsIGVjaG8gPSBUUlVFLCBldmFsID0gRkFMU0V9CmRldnRvb2xzOjppbnN0YWxsX2JpdGJ1Y2tldCgnZGF0dGFtYW5vc2hpL2Nhc2V1JykgIyBJbnN0YWxsIENBU0VVIHBhY2thZ2UKbGlicmFyeShDQVNFVSkKYGBgCgoKIyMgVGVzdCBvbiBleGFtcGxlIGRhdGEKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAwLXRlc3QuUiIpCmBgYAoKCiMjIENBU0VVIHBpbG90MQoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDEvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGUuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClRoZSBpc29sYXRlcyB1c2VkIGluIHRoaXMgcm91bmQgaXMgZnJvbSB0aGUgbGlzdCBiZWxvdy4KCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQpUYWJsZTogaXNvbGF0ZXMKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDEtcGlsb3QxLlIiKQpgYGAKCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90MS5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCiMjIENBU0VVIHBpbG90MgoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIFRoZXJlIGFyZSAzMiBzYW1wbGVzIGZyb20gcGFpcndpc2UgY29tcGV0aXRpb24gYW5kIDE2IHNhbXBsZXMgZnJvbSBjb250cm9sLiBBbHNvIHJlYWQgU3lsdmllJ3MgZGF0YS4gCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9yYXcvU2FuZ2VyL0NBU0VVX3BpbG90Mi9wcm90b2NvbF8yMDE5MDkxMF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCklzb2xhdGVzIEEgQiBDIEQgaW4gY29udHJvbCBhcmUgdGhlIGlzb2xhdGVzIGJlbG93LiAKCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDItcGlsb3QyLlIiKQojc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDJhLXBpbG90Ml9TeWx2aWUuUiIpICMgUnVuIFN5bHZpZSdzIHNlcXVlbmNlCmBgYAoKCkluIHRoZSAxMiBjb250cm9sIHN5bnRoZXRpYyBwYWlycyB0aGF0IHdlcmUgbWFkZSBvZiA0IGlzb2xhdGVzLCBjb21wYXJlIHRoZXNlIHBhaXJzJyBPRCBmcmVxdWVuY2llcywgY29sb255IGNvdW50cywgYW5kIENBU0VVIHByZWRpY3Rpb25zLgoKUmVhZCBDQVNFVSBwcmVkaWN0ZWQgZnJlcXVlbmNpZXMgYW5kIGNvbG9ueSBjb3VudCBmcmVxdWVuY2llcyBpbiB0aGUgMTIgY29udHJvbCBwYWlycy4KCmBgYHtyfQpDQVNFVV9waWxvdDIgPC0gcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90Mi5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCkNBU0VVX3BpbG90Ml9wbGF0aW5nIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDIvQ0FTRVVfcGlsb3QyX3BsYXRpbmcuY3N2IiwgY29sX3R5cGVzID0gY29scygpKSAlPiUKICBtdXRhdGUoSXNvbGF0ZTFDb2xvbnlGcmVxID0gSXNvbGF0ZTFDb2xvbnkgLyAoSXNvbGF0ZTFDb2xvbnkgKyBJc29sYXRlMkNvbG9ueSksCiAgICBJc29sYXRlMkNvbG9ueUZyZXEgPSBJc29sYXRlMkNvbG9ueSAvIChJc29sYXRlMUNvbG9ueSArIElzb2xhdGUyQ29sb255KSkKQ0FTRVVfcGlsb3QyCmBgYAoKCgojIyBDQVNFVSBwaWxvdDMKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwOTIzX1NlcXVhbFByZXBfU2FuZ2VyX3ByZXAucGRmYC4gCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9yYXcvU2FuZ2VyL0NBU0VVX3BpbG90My9wcm90b2NvbF8yMDE5MDkyNF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3J9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuIAppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAzLXBpbG90My5SIikKYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90My5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCiMjIENBU0VVIHBpbG90NAoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDQvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgpSZWFkIHRyYWNlIG1hdHJpY2VzIGZvciBpc29sYXRlcyBhbmQgbWl4dHVyZXMKCmBgYHtyfQojIEl0IHRha2VzIGFib3V0IH4xNSBtaW5zIHRvIHJ1bgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTA0LXBpbG90NC5SIikKYGBgCgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9waWxvdDQuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgojIyBDQVNFVSBzaXggcGxhdGVzCgotIEdlbmV3aXogc3VibWlzc2lvbiBjb2RlOiBDQVNFVV9STl81ICh3aGljaCBpcyBub3QgY29ycmVjdCBiZWNhdXNlIHRoZXNlIGFyZSBub3QgUk4gcGxhdGVzKQotIFBsYXRlczoKICAgIC0gQjIgVDcgOTMzIFAyCiAgICAtIEIyIFQ3IDQ0NCBQMgogICAgLSBDMiBUNyAxM0EgUDIKICAgIC0gQzIgVDcgMTNCIFAyCiAgICAtIEQgVDcgNzUgUDIKICAgIC0gRCBUNyA1NTQzIFAyCi0gTm90ZXM6IHRoZSBwbGF0ZXMgbXVzdCBiZSBwbGFjZWQgaW4gb3JkZXIhIQoKYGBge3J9CiMgR2VuZXJhdGUgc2VxdWVuY2luZyBjc3YKaWYgKEZBTFNFKSB7CmdlbmV3aXpfdGFibGUgPC0gdGliYmxlKFNhbXBsZSA9IDE6KDk2KjYpLCAKICAgICAgIGBETkEgTmFtZWAgPSBwYXN0ZTAocmVwKGMoIkIyX1Q3XzkzM19QMiIsICJCMl9UN180NDRfUDIiLCAiQzJfVDdfMTNBX1AyIiwgIkMyX1Q3XzEzQl9QMiIsICAiRF9UN183NV9QMiIsICJEX1Q3XzU1NDNfUDIiKSwgZWFjaCA9IDk2KSwgIl8iLCByZXAoMTo5NiwgNikpLCAKICAgICAgIGBMZW5ndGggKGJwKWAgPSAxMDAwLCBgQ29uY2VudHJhdGlvbiAobmcvdUwpYCA9IDAuODMsIFByaW1lciA9ICIyN0YiKQoKd3JpdGVfY3N2KGdlbmV3aXpfdGFibGUsIGhlcmU6OmhlcmUoIm91dHB1dC9wcm90b2NvbC90YWJfZmlnLzIwMjExMjAyX1Nhbmdlcl9zZXFfcHJlcC1nZW5ld2l6X3RhYmxlX0NZQy5jc3YiKSkKCn0KYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3NpeHBsYXRlcy5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCgojIyBSYW5kb20gbmV0d29yaywgQ0FTRVUgYmF0Y2ggMQoKLSBHZW5ld2l6IHN1Ym1pc3N0aW9uIGNvZGU6IENhc2V1X1JOXzEKLSBQbGF0ZSBsYXlvdXQ6IFQzIEMgUDIKLSBEZXNjcmlwdGlvbjogc2FtcGxlcyAzLCA0LCA1LCAxMiwgMTMsIDI3LCAyOSwgMzMsIDczLCA4NSwgODYsIDkxLCBhbmQgOTQgKG9yZGVyIGJ5IGNvbHVtbiBpbiB0aGUgcGxhdGUgbGF5b3V0KSBhcnJpdmVkIEdlbmV3aXogZHJ5LCBzbyB0aGV5IGFyZSBub3QgcHJvY2Vzc2VkLgoKYGBge3J9CiMgSWYgd2lsbCB0YWtlIH4yIGhyIHRvIHJ1bgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1yYW5kb21fbmV0d29ya19DQVNFVS0wMS1iYXRjaDEuUiIpCmBgYAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9STjEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDIKCi0gR2VuZXdpeiBzdWJtaXNzaW9uIGNvZGU6IENhc2V1X1JOXzIKLSBQbGF0ZSBsYXlvdXQ6IFQzIEMgUDIKLSBEZXNjcmlwdGlvbjogdGhpcyBwbGF0ZSBsYXlvdXQgY29udGFpbnMgdGhlIGlzb2xhdGVzIGZvciBhbGwgNCByYW5kb20gYXNzZW1ibGVkIGNvbW11bml0aWVzIAoKYGBge3J9CiMgSXQgdGFrZXMgfjMwIG1pbnMKaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkItcmFuZG9tX25ldHdvcmtfQ0FTRVUtMDItYmF0Y2gyLlIiKQpgYGAKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvQ0FTRVVfUk4yLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDMKCi0gR2VuZXdpeiBzdWJtaXNzdGlvbiBjb2RlOiBDYXNldV9STl8zCi0gUGxhdGUgbGF5b3V0OiAKICAgIC0gUDEgKFQwIEMgUDIpLCB0cmFja2luZyBudW1iZXIgMzAtMzMzNjQ5MTQzCiAgICAtIFAyIChUMCBBRCBQMiksIHRyYWNraW5nIG51bWJlciAzMC0zMzM2NDkzNjUKICAgIC0gUDMgKFQzIEFEIFAyKSwgdHJhY2tpbmcgbnVtYmVyIDMwLTMzMzY0OTUxNwotIERlc2NyaXB0aW9uOiBBRCBwbGF0ZXMgaGF2ZSB0aGUgaXNvbGF0ZXMgYXNzZW1ibGVkIGZyb20gdGhlIHNlbGYtYXNzZW1ibGVkIGNvbW11bml0aWVzIGJ1dCBkaWZmZXJlbnQgY29tbXVuaXRpZXMKCmBgYHtyfQojIEl0IHRha2VzIH4xLjUgaHIKaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkItcmFuZG9tX25ldHdvcmtfQ0FTRVUtMDMtYmF0Y2gzLlIiKQpgYGAKClVzZSBUMCBPRCBmcmVxdWVuY2llcwoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9STjMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDQKCi0gR2VuZXdpeiBzdWJtaXNzdGlvbiBjb2RlOiBDYXNldV9STl80Ci0gUGxhdGUgbGF5b3V0OiBUMyBCRCBQMwotIERlc2NyaXB0aW9uOiBUaGlzIHBsYXRlIGhhcyB0aGUgZnVsbCBBY3JBc3MyIChCKSBhbmQgaGFsZiBvZiBSYW5Bc3MyIChEKSBuZXR3b3JrLgoKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1yYW5kb21fbmV0d29ya19DQVNFVS0wNC1iYXRjaDQuUiIpCmBgYAoKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvQ0FTRVVfUk40LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCgojIDAyQyBwYWlyc19PRF9DRlUKCi0gRXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5CgotIERlcml2ZSBpc29sYXRlcycgJFxlcHNpbG9uJCBmcm9tIFQ4IGRhdGEgYW5kIGNhbGN1bGF0ZSB1bmNlcnRhdGludHkgdXNpbmcgZXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5CgotIENvbnZlcnQgVDAgT0QgZnJlcXVlbmN5ICRmXk8kIHRvIENGVSBmcmVxdWVuY3kgJGZeQyQgYW5kIGVzdGltYXRlIHRoZSB1bmNlcnRhaW50eSBpbiBjb252ZXJ0ZWQgQ0ZVIGZyZXF1ZW5jaWVzIGF0IFQ4LiBPdXRwdXQgYGRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3ZgCgojIyBHZW5lcmFsIGZvcm11bGEgb2YgZXJyb3IgcHJvcGFnYXRpb24KClRoaXMgc2VjdGlvbiBleHBsYWlucyB0aGUgZXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5IHRvIGVzdGltYXRlIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgZXhwZXJpbWVudGFsIG1lYXN1cmVtZW50LiBUaGVyZSBhcmUgb25lIG9yIG1vcmUgcXVhbnRpdGllcyAkeCwgeSwgLi4uJCwgd2l0aCBjb3JyZXNwb25kaW5nIHVuY2VydGFpbnRpZXMgJFxkZWx0YSB4LCBcZGVsdGEgeSwgLi4uJCBhbmQgdGhhdCB3ZSB3aXNoIHRvIHVzZSB0aGUgbWVhc3VyZWQgdmFsdWVzIG9mIHggYW5kIHkgdG8gY2FsY3VsYXRlIHRoZSBxdWFudGl0eSBvZiByZWFsIGludGVyZXN0IHEuIFRoZXJlIGFyZSB0aHJlZSBwcm92aXNpb25hbCBydWxlczoKCjEuIFRoZSBzcXVhcmUtcm9vdCBydWxlIGZvciBjb3VudGluZyBleHBlcmltZW50cy4gVGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGV2ZW50IGluIHRpbWUgVCBpcyAkdlxwbVxzcXJ0e3Z9JAoKMi4gVW5jZXJ0YWludHkgaW4gKipzdW1zIGFuZCBkaWZmZXJlbmNlcyoqLiBUaGUgY29tcHV0ZWQgbWVhbiB2YWx1ZSAkcT14K3krei0odSt3KSQuIElmIHRoZSB1bmNlcnRhaW50aWVzIGluIHgsIC4uLiwgdyBhcmUga25vd24gdG8gYmUgaW5kZXBlbmRlbnQgYW5kIHJhbmRvbSwgdGhlbiB0aGUgdW5jZXJ0YWludHkgaW4gdGhlIGNvbXB1dGVkIHZhbHVlIG9mIHEgaXMgdGhlIHF1YWRyYXRpYyBzdW0gJFxkZWx0YSBxID0gXHNxcnR7KFxkZWx0YSB4KV4yKyhcZGVsdGEgeSleMisoXGRlbHRhIHopXjIrKFxkZWx0YSB1KV4yKyhcZGVsdGEgdyleMn0kICwgSW4gYW55IGNhc2UsICRcZGVsdGEgcSQgaXMgbmV2ZXIgbGFyZ2VyIHRoYW4gdGhlaXIgb3JkaW5hcnkgc3VtICRcZGVsdGEgcSBcbGVxc2xhbnQgXGRlbHRhIHggKyBcZGVsdGEgeSsgXGRlbHRhIHogKyBcZGVsdGEgdSArIFxkZWx0YSB3JAoKMy4gVW5jZXJ0YWludHkgaW4gKipwcm9kdWN0IGFuZCBxdW90aWVudHMqKi4gJHE9XGZyYWN7eFx0aW1lcyB6fXt1XHRpbWVzIHd9JCwgdGhlbiB0aGUgZnJhY3Rpb25hbCB1bmNlcnRhaW50eSBpbiB0aGUgY29tcHV0ZWQgdmFsdWUgcSBpcyB0aGUgc3VtLiBJZiB0aGUgdW5jZXJ0YWludGllcyBpbiB4LCAuLi4sdyBhcmUgaW5kZXBlbmRlbnQgYW5kIHJhbmRvbSwgdGhlbiB0aGUgZnJhY3Rpb25hbCB1bmNlcnRhaW50eSBpbiBxIGlzIHRoZSBzdW0gaW4gcXVhZHJhdHVyZSBvZiB0aGUgb3JpZ2luYWwgdW5jZXJ0YWludGllcywgJFxmcmFje1xkZWx0YSBxfXtcbGVmdHxxXHJpZ2h0fH0gPSBcc3FydHsoXGZyYWN7XGRlbHRhIHh9e1xsZWZ0fHhccmlnaHR8fSleMiArIFxmcmFje1xkZWx0YSB5fXtcbGVmdHx5XHJpZ2h0fH0pXjIgK1xmcmFje1xkZWx0YSB6fXtcbGVmdHx6XHJpZ2h0fH0pXjIgK1xmcmFje1xkZWx0YSB1fXtcbGVmdHx1XHJpZ2h0fH0pXjIgKyBcZnJhY3tcZGVsdGEgd317XGxlZnR8d1xyaWdodHx9KV4yfSQuICRcZnJhY3tcZGVsdGEgcX17XGxlZnR8IHEgXHJpZ2h0fH0gXGxlcXNsYW50IFxmcmFje1xkZWx0YSB4fXtcbGVmdHwgeCBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB6fXtcbGVmdHwgeiBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB1fXtcbGVmdHwgdSBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB3fXtcbGVmdHwgdyBccmlnaHR8fSQgCgpUYWtpbmcgdGhlc2UgdGhyZWUgcHJvdmlzaW9uYWwgcnVsZXMgdG9nZXRoZXIsIHRoZSBnZW5lcmFsIGZvcm11bGEgZm9yIGVycm9yIHByb3BhZ2F0aW9uIHRha2VzIHRoZSBmb2xsb3dpbmcgZm9ybS4gQXNzdW1lIHRoZSBjb21wdXRlZCBxdWFudGl0eSBpcyBhIGZ1bmN0aW9uIG9mICR4XzEsIHhfMiwgLi4uLCB4X24kLCB0aGUgdW5jZXJ0YWludHkgaW4gcSBpcyAkJFxkZWx0YSBxPSBcc3FydHsoXHN1bXtcZnJhY3tccGFydGlhbCBxfXtccGFydGlhbCB4X2l9fVxkZWx0YSB4X2kpXjJ9JCQgCgoKCiMjIFVuY2VydGFpbnR5IGluIGVwc2lsb24gCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAxLWVwc2lsb25fdW5jZXJ0YWludHkuUiIpCmBgYAoKClRoZSB1bmNlcnRhaW50aWVzIGluIGVhY2ggaXNvbGF0ZScgZXBzaWxvbiAkXGVwc2lsb25fQSA9IFxmcmFje09EX0EgREZfQSB2X0F9e0NGVV9BfSQgY29tZXMgZnJvbSBmb3VyIHBhcnRzOgoKMS4gJERGJDogRGlsdXRpb24gZmFjdG9ycy4gVGhlIHVuY2VydGFpbnR5IGNvbWVzIGZyb20gdGhlIHBpcGV0dGluZyBpbiBzZXJpYWwgZGlsdXRpb24sIHdoaWNoIGlzIGNhbGNhdWx0ZWQgYmVsb3cuCjIuICR2JDogUGxhdGluZyB2b2x1bWVzLiBUaGUgc3lzdGVtYXRpYyBlcnJvciBmb3IgUDIwIHNldCBhdCAyMCB1TCBpcyAwLjQgdUwuCjMuICRDRlUkOiBDRlUgY291bnRzLiBUaGUgdW5jZXJ0YWludHkgaW4gQ0ZVIGZvbGxvd3MgcG9pc3NvbiBkaXN0cmlidXRpb24sIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHZhcmlhbmNlIGlzIHRoZSBzYW1lIGFzIHRoZSBtZWFuIChtZWFzdXJlZCBDRlUpLiBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzICRcc3FydHtDRlV9JC4KNC4gJE9EJDogT0QgbWVhc3VyZW1lbnQuIFRoZSB1bmNlcnRhaW50eSBpbiBtZWFzdXJpbmcgT0QgaW4gcGxhdGUgcmVhZGVyLCB3aGljaCBpcyBhc3N1bWVkIHRvIGJlIDAuMDAxLgoKCioqRGlsdXRpb24gZmFjdG9yKioKClRoZSB1bmNlcnRhaW50eSBpbiBkaWx1dGlvbiBmYWN0b3IgY29tZXMgZnJvbSB0aGUgcGlwZXR0aW5nIHN0ZXBzIGluIHNlcmlhbCBkaWx1dGlvbiwgd2hpY2ggaW5jbHVkZSB0d28gcGlwZXR0aW5nIHZvbHVtZXM6CgoxLiBgVjFgOiBzZXJpYWwgZGlzcGVuc2luZyAxMCB1TCBvZiBkaWx1dGVkIHNvbHV0aW9uIHVzaW5nIG1QMjAuIEl0IGhhcyB1bmNlcnRhaW50eSBgRXJyb3JWMWAgMiB1TC4KMi4gYFYyYDogZGlzcGVuc2UgOTAgdUwgb2YgUEJTIHVzaW5nIG1QMjAwLiBJdCBoYXMgdW5jZXJ0YWludHkgYEVycm9yVjJgIDAuNCB1TC4KCkZvciBkaWx1dGlvbiBmYWN0b3IgJDEwXntufSQsIGl0IGhhcyB0aGUgdGhlIG1lYW4gJChcZnJhY3tWXzF9e1ZfMStWXzJ9KV5uJC4gVG8gb2J0YWluIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgbWVhc3VyZWQgbWVhbiwgZmlyc3Qgd2UgY2FsdWN1bGF0ZSB0aGUgcGFydGlhbCBkZXJpdmF0aXZlcyAkXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMX0kIGFuZCAkXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMn0kLiBUaGVuIHRoZSB1bmNlcnRhaW50eSAkXGRlbHRhIERGID0gXHNxcnR7KFxmcmFje1xwYXJ0aWFsIERGfXtccGFydGlhbCBWXzF9XGRlbHRhIFZfMSleMiArIChcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8yfVxkZWx0YSBWXzIpXjJ9JAoKCmBgYHtyfQpkaWx1dGlvbl9mYWN0b3IgPC0gdGliYmxlKG4gPSBjKDQsIDUpLCBWMSA9IDEwLCBWMiA9IDkwLCBFcnJvclYxID0gMC40LCBFcnJvclYyID0gMikgJT4lCiAgbXV0YXRlKFBhcnRpYWxWMSA9IG4gKiBWMV4obi0xKSAqIFYyIC8gKFYxK1YyKV4obisxKSwgIy1uKihWMStWMileKG4tMSkqVjIvKFYxXihuKzEpKSwKICAgICAgICAgUGFydGlhbFYyID0gLW4gKiBWMV4obi0xKSAvIChWMStWMileKG4rMSksICNuKihWMStWMileKG4tMSkvKFYxXm4pLAogICAgICAgICBERiA9IChWMS8oVjErVjIpKV5uLAogICAgICAgICBFcnJvckRGID0gc3FydCgoUGFydGlhbFYxKkVycm9yVjEpXjIgKyAoUGFydGlhbFYyKkVycm9yVjIpXjIpKQoKZGlsdXRpb25fZmFjdG9yCmBgYAoKCkJ5IHVzaW5nIGVycm9yIHByb3BhZ2F0aW9uIHRoZXJveSwgdGhlIHVuY2VydGFpbnR5IGluIGlzb2xhdGVzIGVwc2lsb24gaGFzIHRoZSBmb3JtIAoKJCRcZGVsdGEgXGVwc2lsb24gPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgIFxlcHNpbG9ufXtccGFydGlhbCBERn1cZGVsdGEgREYpXjIgKyhcZnJhY3tccGFydGlhbCAgXGVwc2lsb259e1xwYXJ0aWFsIENGVX1cZGVsdGEgQ0ZVKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgT0R9XGRlbHRhIE9EKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgVn1cZGVsdGEgVileMn0kJAoKCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9pc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKaXNvbGF0ZXNfZXBzaWxvbl91bmNlcnRhaW50eQpgYGAKClRoZXJlIGFyZSA3IGlzb2xhdGVzIHRoYXQgaGF2ZSBlaXRoZXIgMCBDRlUgb3IgbmVnYXRpdmUgT0QgdmFsdWUsIHNvIHRoZXkgZG9uJ3QgaGF2ZSBlcHNpbG9uIHZhbHVlcy4KCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5ICU+JQogIGZpbHRlcihpcy5uYShFcHNpbG9uKSkKYGBgCgojIyBDb252ZXJ0IFQwIE9EIGZyZXF1ZW5jaWVzIHRvIENGVSBmcmVxdWVuY2llcwoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJDLXBhaXJzX09EX0NGVS0wMi1DRlVfZnJlcXVlbmN5LlIiKQpgYGAKClRoZSBvdXRjb21lIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIHdlcmUgZGV0ZXJtaW5lZCBieSBjb21wYXJpbmcgdGhlIGZyZXF1ZW5jeSBjaGFuZ2VzIGJldHdlZW4gVDAgYW5kIFQ4LiBUaGUgVDggZnJlcXVlbmNpZXMgd2VyZSBkZXRlcm1pbmVkIGJ5IHBsYXRpbmcgdGhlIG1hdHVyZSBtZWRpYSBvbiByaWNoIGFnYXIgbWVkaWEgb24gd2hpY2ggdGhlIGNvbG9uaWVzIHdlcmUgY291bnRlZCwgd2hlcmVhcyBUMCBmcmVxdWVuY2llcyB3ZXJlIHNldCB0byA5NS81LCA1MC81MCBhbmQgNS85NSBieSBtaXhpbmcgdHdvIGlzb2xhdGUgaW5vY3VsYSB3aXRoIGVxdWFsIE9ELiAgSW4gdGhpcyBzZWN0aW9uLCBJIHdpbGwgdXNlIHRoZSBPRC1DRlUgY29udmVyc2lvbiBjb2VmZmljaWVudCAkXGVwc2lsb24kIGRlcml2ZWQgZnJvbSBUOCBpc29sYXRlIGRhdGEgdG8gY29udmVydCBUMCBPRCBmcmVxdWVuY2llcyBpbnRvIENGVSBmcmVxdWVuY2llcy4gSW4gc3BlY2lmaWMsIHRoZSBDRlUgZnJlcXVlbmN5IG9mIGlzb2xhdGUgMSAkZl5DXzEkIG9mIGEgcGFpciBjYW4gYmUgZGVyaXZlZCBmcm9tIE9EIGZyZXF1ZW5jaWVzIG9mIGlzb2xhdGUgMSBhbmQgMiAkZl5PXzEgLGZeT18yJCwgd2hpY2ggaGF2ZSB0aGUgcmVsYXRpb25zaGlwIGJlbG93LiAKCiRmXkNfMSA9IFxmcmFje2Zeb18xXGVwc2lsb25fMURGdn17Zl5vXzFcZXBzaWxvbl8xREZ2ICsgZl5vXzJcZXBzaWxvbl8yREZ2fT1cZnJhY3tmXm9fMVxlcHNpbG9uXzF9e2Zeb18xXGVwc2lsb25fMSArIGZeb18yXGVwc2lsb25fMn0kCgp3aGVyZSAkXGVwc2lsb24kIG9mIGVhY2ggaXNvbGF0ZSB3YXMgcHJlLWNhbGN1bGF0ZWQgZnJvbSBUOCBkYXRhc2V0LiBERiBhbmQgdiBhcmUgdGhlIHNhbWUgaW4gY29udmVyc2lvbi4KCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfQ0ZVX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgojIyBVbmNlcnRhaW50eSBpbiBUMCBDRlUgZnJlcXVlbmNpZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQy1wYWlyc19PRF9DRlUtMDMtQ0ZVX2ZyZXF1ZW5jeV91bmNlcnRhaW50eS5SIikKYGBgCgpXcml0ZSBDRlUgZnJlcXVlbmNpZXMgdG8gYGRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3ZgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKIyAwMkQgZGV0ZXJtaW5lIHBhaXJ3aXNlIGludGVyYWN0aW9uCgojIyBDb21iaW5lIG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIGZyb20gQ0ZVIGNvdW50cyBhbmQgQ0FTRVUKClJhdyBkYXRhIChlLmcuLCBDRlUgY291bnRzIGFuZCBDQVNFVSBTYW5nZXIgc2VxdWVuY2VzKSBhcmUgcHJvY2Vzc2VkIGFuZCBnZW5lcmF0ZWQgaW50byB0ZW1wb3JhcnkgcmVzdWx0IGNzdjoKCjEuIGAwMkItQ0FTRVVfc2FuZ2VyX3NlcWAgcmVhZHMgQ0FTRVUgcmF3IGRhdGEgYW5kIG91dHB1dHMgYHRlbXAvQ0FTRVVfcGlsb3QyLmNzdmAgYW5kIGB0ZW1wL0NBU0VVX3BpbG90My5jc3ZgLiBCb3RoIGZpbGVzIGFyZSBDQVNFVSBwcmVkaWN0ZWQgVDggZnJlcXVlbmNpZXMuCgoyLiBgMDJDLXBhaXJzX09EX0NGVWAgcmVhZHMgcGFpcl9jb21wZXRpdGlvbiBhbmQgZGlsdXRpb24gZmFjdG9yIGRhdGEsIGFuZCBpdCBvdXRwdXRzIGB0ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAsIHdoaWNoIGhhcyB0aGUgVDAgT0QtY29udmVydGVkIENGVSBmcmVxdWVuY2llcyBhbmQgVDggQ0ZVIGZyZXF1ZW5jaWVzIHdpdGggdW5jZXJ0YWludGllcy4KCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkQtZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLTAxLWNvbWJpbmVfQ0ZVX0NBU0VVX3Jlc3VsdC5SIikKYGBgCgpUaGUgc2NyaXB0IGluIHRoaXMgc2VjdGlvbiByZXR1cm5zIGEgZGF0YS5mcmFtZSBgcGFpcnNfZnJlcWAgdGhhdCBoYXMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6CgotIGBDb21tdW5pdHlgCi0gYElzb2xhdGUxYCBhbmQgYElzb2xhdGUyYDogaW5kaWNlcyBvZiBpc29sYXRlcyB3aXRoaW4gYSBjb21tdW5pdHkuIFRoZSBudW1iZXIgb2YgaXNvbGF0ZTEgaXMgYWx3YXlzIHNtYWxsZXIgdGhhbiBpc29sYXRlMgotIGBJc29sYXRlMUluaXRpYWxPREZyZXFgIGFuZCBgSXNvbGF0ZTJJbml0aWFsT0RGcmVxYDogNSwgNTAgb3IgOTUuIFRoZSBpbml0aWFsIE9EIGZyZXF1ZW5jaWVzIG9mIGlzb2xhdGVzIGF0IFQwLiBUaGlzIHR3byBzZXJ2ZSBhcyBkaXNjcmV0ZSBncm91cGluZyB2YXJpYWJsZXMuCi0gYFRpbWVgOiBUMCBvciBUOC4KLSBgSXNvbGF0ZTFNZWFzdXJlZEZyZXFgOiB0aGUgbWVhc3VyZWQgZnJlcXVlbmN5IG9kIGlzb2xhdGUxIGluIHRoZSBwYWlyLiAKLSBgRXJyb3JJc29sYXRlMU1lYXN1cmVkRnJlcWA6IHRoZSB1bmNlcnRhaW50eSBvZiBgSXNvbGF0ZTFNZWFzdXJlZEZyZXFgLgotIGBSYXdEYXRhVHlwZWA6IE9ELCBPRHRvQ0ZVLCBDRlUsIFNhbmdlciAoQ0FTRVUpLiBUaGUgcmF3IGRhdGEgdHlwZSBpbiB3aGljaCB0aGUgaXNvbGF0ZSBmcmVxdWVuY2llcyB3ZXJlIG1lYXN1cmVkLgotIGBDb250YW1pbmF0aW9uYDogbG9naWNhbC4gVGhlcmUgYXJlIGNvbnRhbWluYXRpb24gaW4gdGhyZWUgcGFpcnMgYXQgVDggcGxhdGVzLgoKMTg2eDN4Mj0xMTE2IHBhaXItZnJlcSBhdCB0d28gdGltZSBwb2ludHMgZm9yIHRoZSBzZWxmLWFzc2VtYmxlZCBjb21tdW5pdHkgbmV0d29ya3MuCgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKCiMjIERldGVybWluZSBwYWlyd2lzZSBpbnRlcmFjdGlvbnMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRC1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24tMDItZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLlIiKQpgYGAKClRhYmxlIG9mIGFsbCAyNyArIDQgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGZpdG5lc3MgZnVuY3Rpb24gYW5kIHRoZWlyIGludGVyYWN0aW9uIHR5cGVzIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ludGVyYWN0aW9uX3RhYmxlLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKVGFibGUgb2YgaW50ZXJhY3Rpb24gdHlwZXMKCmBgYHtyfQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfaW50ZXJhY3Rpb25fZml0bmVzcyAlPiUKICBncm91cF9ieShTZXQsIEludGVyYWN0aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpLCAuZ3JvdXBzID0gImtlZXAiKSAKYGBgCgojIyBJc29sYXRlIHRvdXJuYW1lbnQKCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkQtZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLTAzLWlzb2xhdGVfdG91cm5hbWVudC5SIikKYGBgCgpUb3VybmFtZW50IHJhbmtzIG9mIGVhY2ggaXNvbGF0ZS4gTm90ZSB0aGF0IEkgY29uc2lkZXIgbmV0dXJhbGl0eSBhbmQgYmlzdGFiaWxpdHkgYXMgZHJhdyBpbiB0aGUgdG91cm5hbWVudC4KCi0gYFNjb3JlYDogdGhlIGNvbXBldGl0aXZlIHNjb3JlcyBvZiBpc29sYXRlLiBUaGlzIHNjb3JlIGlzIGNvbXB1dGVkIGJ5IHRoZSBmb3JtdWxhOiBudW1iZXIgb2Ygd2lucyAtIG51bWJlciBvZiBsb3NlcyArIDAgKiBudW1iZXIgb2YgZHJhd3MuIAotIGBHYW1lYDogbnVtYmVyIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIHRoZSBpc29sYXRlIGhhcyBwbGF5ZWQuIFRoZSBudW1iZXIgb2YgZ2FtZXMgYW4gaXNvbGF0ZSBwbGF0ZWQgd2l0aGluIGEgY29tbXVuaXR5IHNob3VsZCBiZSBjb21tdW5pdHkgc2l6ZSBtaW51cyBvbmUuIAotIGBSYW5rYDogdGhlIHJhbmtzIGJhc2VkIG9uIGBTY29yZWAuIFRoZSByYW5rcyByYW5nZSBmcm9tIDEgdG8gdGhlIGZvY2FsIGNvbW11bml0eSBzaXplLiBJc29sYXRlcyB3aXRoIHRoZSBzYW1lIHNjb3JlcyBpbiBhIGNvbW11bml0eSBhcmUgZ2l2ZW4gdGhlIHNhbWUgcmFuay4KLSBgUGxvdFJhbmtgOiBjb250aW51b3VzIHJhbmsgZm9yIHBsb3R0aW5nIGNvbnZlbmllbmNlLgoKCiMgMDJFIGNvbXBldGl0aW9uIHBoeWxvZ2VueQoKLSBDb3JyZWxhdGUgY29tcGV0aXRpb24gcmVzdWx0IHdpdGggcGh5bG9nZW5ldGljIGRpc3RhbmNlCgotIE1lYXN1cmUgdGhlIHBhaXJ3aXNlIHBoeWxvZ2VuZXRpYyBkaXN0YW5jZXMgYnkgZGlmZmVyZW5jZSBpbiAxNlMgYmFzZSBwYWlycyBgcGFpcnNfdGF4b25vbXlgCiAgICAtIENvYXJzZS1ncmFpbmVkIHRheG9ub215IChGYW1pbHkgYW5kIEdlbnVzKQogICAgLSBDb21wdXRlIHRoZSBwYWlyd2lzZSBzZXF1ZW5jZSBkaWZmZXJlbmNlcyB1c2luZyBgQmlvc3RyaW5nOjpwYWlyd2lzZUFsaWdubWVudCgpYCAKICAgIC0gQ29tcHV0ZSBwYWlyd2lzZSB0cmVlIGRpc3RhbmNlIHVzaW5nIGBhcGU6OmNvcGhlbmV0aWMucGh5bG8oKWAgb24gYnVpbHQgdHJlZS4gVHJ5IG91dCBkaWZmZXJlbnQgdHJlZSBidWlsZGluZyBtZXRob2RzCgoKIyMgSXNvbGF0ZXMnIFJEUCB0YXhvbm9teQoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJFLWNvbXBldGl0aW9uX3BoeWxvZ2VueS0wMS1wYWlyc190YXhvbm9teS5SIikKYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX3RheG9ub215LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCiMjIElzb2xhdGVzJyAxNlMgc2VxdWVuY2UgZGlmZmVyZW5jZQoKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRS1jb21wZXRpdGlvbl9waHlsb2dlbnktMDItcGFpcnNfMTZTLlIiKQpgYGAKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfMTZTLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCgojIFN1bW1hcnkKCiMjIFJlYWQgYW5kIGNvbWJpbmUgcGFpcnMgZGF0YSAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAxLXJlYWRfZGF0YS5SIikKYGBgCgoxODYgcGFpcnMgb2Ygc2VsZi1hc3NlbWJsZWQgY29tbXVuaXRpZXMgYW5kIDExMiBwYWlyIGZyb20gYWNyb3NzLWNvbW11bml0eSBhbmQgcmFuZG9tIG5ldHdvcmtzCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClBhaXJzIHdpdGggdGhyZWUgaW5pdGlhbCBmcmVxdWVuY2llcyBhbmQgdGhyZWUuIDE4NngzeDI9MTExNgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKSAlPiUKICAgIGZpbHRlcihTZXQgPT0gIkNGVWFuZENBU0VVIikKYGBgCgpwYWlyc19tZXRhIGNvbnRhaW5zIHRoZSBncm93dGggdHJhaXRzIG9mIGlzb2xhdGVzLiBOb3RlIHRoYXQgdGhlIG9yZGVyIG9mIElzb2xhdGUxIGFuZCBJc29sYXRlMiBpbiBzb21lIHBhaXJzIGFyZSBmbGlwcGVkIHN1Y2ggdGhhdCBJc29sYXRlMSBpcyBhbHdheXMgdGhlIGRvbWluYW50IHN0cmFpbiBhbmQgSXNvbGF0ZSAyIGlzIHRoZSBzdWJkb21haW50IG9uZS4gRG9taW5hbnQgc3RyYWluIGlzIHRoZSB3aW5uZXIgaW4gZXhjbHVzaW9uIHBhaXJzLCBhbmQgdGhlIG1vcmUgYWJ1bmRhbnQgc3RyYWluICg1MDo1MCB0cmVhdG1lbnQpIGluIGNvZXhpc3RlbmNlIHBhaXJzLgoKYGBge3J9CmlmIChGQUxTRSkgcGFpcnNfbWV0YSA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL291dHB1dC9wYWlyc19tZXRhLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgpFeGFtcGxlIG91dGNvbWUgdHlwZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAyLW91dGNvbWVfdHlwZXMuUiIpCmBgYAoKQ29hcnNlLWdyYWluZWQgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnNfZXhhbXBsZV9vdXRjb21lcy5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYApGaW5lLWdyYWluZWQgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lci5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCgoKCgo=